良好程式碼的優點大同小異。
不好的程式碼的糙點卻各有巧妙之處。
官網文件,通常是該套件或框架的聖經文件。(偶爾會遇到寫得很爛,又很流行的框架或套件)
先來看看聖經怎麼說。
Jacob Dufour: "Who said it: Jesus or Satan?"
youtube 原文版 | facebook 加上中文字幕版
提摩太後書 4:3-4
因為時候要到,人必厭煩純正的道理,耳朵發癢,就隨從自己的情慾,增添好些師傅,並且掩耳不聽真道,偏向荒渺的言語。
當我們遇見問題,不在乎真理如何記載,也不上網查閱,自己腦補,或聽見似是而非的道理,而隨便相信它,這種態度必須停止。
提摩太後書 3:16
聖經都是神所默示的(或作:凡神所默示的聖經),於教訓、督責、使人歸正、教導人學義都是有益的,
聖經很重要,我們的救恩,取決於我們對這本書的理解...
聖經的作用
了解信仰該如何進行,保持正確的價值觀與態度。
好在日常生活之中可以把書中的價值活出來。
在日常遇到各式各樣的問題時,可以將問題對照到聖經的記載並且找到正確的價值觀。
在實戰中解決疑惑之後,又可以用正確的方式或態度,繼續在日常中把書中的價值活出來。
真的不知道,那些不看文件的人,怎麼掌握好一個套件或框架。
如何正確的使用一個套件或框架,可以從官網文件、部落格教學、教學影片甚至是買書。
有時官網文件實在不是寫得很好,所以很多部落格會再重新詮釋套件的思路或官網文件的補充。而教學影片確實是更加深入的解說官網文件的內容。
真正正確的學習態度,就算你看了部落格文章、教學影片,並且自己做實驗來驗證,還要再重新再回到官網文件找找相關的描述,是不是看得懂了?
官網文件的版本,是會一直在該網站更新,而部落格、教學影片、書籍都不會這麼的即時更新,這也是官網文件的優點。
不過以上的描述不包含很糙的官網文件。
(我自己覺得 AngularJS、Sequelize 很糙)
解釋一下[1]
自作聰明: 自以為聰明而亂作主張。指過高地估計自己,主觀地辦事。
取材自 turtle0617/wonderKnow_statistics - Github
function isFrontend(item) {
const frontEndCondition = ["Front-end", "CSS", "HTML", "Vue"];
return frontEndCondition.includes(item.class);
// if(item.class === "Front-end" || item.class==="CSS" || item.class==="HTML" || item.class==="Vue"){
// return item;
// }
}
export default {
props: ["talks"],
computed: {
frontendTalks: function() {
let frontendTalks = this.talks.filter(isFrontend);
// let frontendTalks = this.talks.filter(data => isFrontend(data));
return frontendTalks.reverse();
}
}
};
這個例子,全域 function 使用 this
就爆了!!!
在資料夾的安排上,有一個 member 的 route 裡,多了一個 get.js
這個案例,有做了一些馬賽克,命名有點糙。
不過命名不是要介紹的糙點。
routes/
├── index.js
├── member/
│ ├── index.js
│ └── list.js
...
routes/index.js
const router = require('express').Router()
const member = require('./member')
router.get('/member', member.list)
module.exports = router
routes/member/index.js
let express = require('express')
let router = express.Router()
const list = require('./list')
router.get('/list', list)
module.exports = router
routes/member/list.js
const members = require('controllers/members')
module.exports = member_list;
async function member_list (req, res, next) {
try {
res.json(await members.list({
id: req.query.id,
}))
} catch (error) {
next(error)
}
}
這個例子,要仔細觀察的是
routes/member/index.js
引用進來。routes/member/list.js
是一個多餘的一層,如果它是必要的,應該是 middleware這裡的用法: route 呼叫一個 function ,再呼叫 controller
而且,express.js 官網的文件並沒有這種寫法,如果 member_list
裡的邏輯是必要存在的話,就做成 middleware 應該在 routes/member/index.js
就出現 controller 而 list
屬於 middleware/list
routes/member/index.js
let router = require('express').Router()
const list = require('middleware/list')
const members = require('controllers/members')
router.get('/list', list, members)
module.exports = router
另一種,確實在 route 看見 controller,但是,這個 route 也太多行了吧?
哦~不要有贅字!!!
routes/index.js
const router = require('express').Router()
const members = require('controllers/members')
router.get('/member', async function (req, res, next) {
try {
res.json(await members.list({
id: req.query.id,
}))
} catch (error) {
next(error)
}
})
module.exports = router
也許是你的想法,當然這樣寫也會跑
不過,自作聰明不就這個意思嗎?。(攤手)
一樣是不照文件寫,因為框架與文件有它的極限在,但是好的寫法總是讓人覺得好,集中管理某些東西,又沒有 side effect,一目了然又好理解 (好猜得中在寫什麼東西,不容易改壞)。
在 Nuxt.js 中 (如果有興趣的朋友可以看看Nuxt - 使用 Vue.js 做 SSR 的第一哩路 這一系列)
按照 Nuxt 預設結構,相比 Vue.js 專案,已經幫你訂好了規則,方便對應與依循...各資料夾對應到官網文件[2]
試想一下,在他或者他參考的框架訂出規則之前,這些規則就是由高手所想到的聰明點子。
- assets: 放需要 webpack 編譯的靜態資源
- static: 不需要編譯的靜態資源
- pages: 各頁對應的頁面元件 (相當於你寫 SPA 時,VueRouter路由指定的元件)
- components: 跨頁面的元件,不具狀態
- nuxt.config.js: Nuxt 全域設定檔
- .nuxt: Nuxt 暫存資料夾
其中的「components: 跨頁面的元件,不具狀態」像是引入 functional programming 的 pure function 觀念,寫 pure component。以剛剛的全域 function 的案例,只要將 isFrontend
移進 methods, components 裡面沒有 data 所有的資料都是從 props 進來,就符合 pure function 的概念,適合拿來共用,保證輸出不會有 side effect。
export default {
props: ["talks"],
computed: {
frontendTalks: function() {
let frontendTalks = this.talks.filter(isFrontend);
return frontendTalks.reverse();
}
},
methods: {
isFrontend(item) {
const frontEndCondition = ["Front-end", "CSS", "HTML", "Vue"];
return frontEndCondition.includes(item.class);
}
}
};
在主流前端框架中,有一個常見的問題,就是發送 ajax 的套件散落各地。
那麼,其實是有方式可以集中管理的。
https://www.slideshare.net/dwatow/vuex-api
在 Vuex 中,獨立一個 action.js
store/actions.js
import axios from 'axios'
export default {
async GET ({ getters }, path) {
const response = await axios.get(`${getters.host}${path}`, {
headers: { /*...*/ },
})
if (response.status === 200) {
return response.data
} else {
return response
}
},
async POST ({ getters }, { path, data }) {
const response = await axios.post(`${getters.host}${path}`,
data, {
headers: { /*...*/ },
})
if (response.status === 200) {
return response.data
} else {
return response
}
},
async PUT ({ getters }, { path, data }) {
const response = await axios.put(`${getters.host}${path}`,
data, {
headers: { /*...*/ },
})
if (response.status === 200) {
return response.data
} else {
return response
}
},
}
在其它的 actions
下,呼叫 dispatch
就可以使用 axios
這樣寫起來,有一種可以讓程式碼與文件長得很像,又可以再用 doSomething 的 funciton name 再抽象一次。提供給其它的 action 呼叫。
export default {
async doSomething1 ({ dispatch, getters }, { data }) {
//...
await dispatch('POST', { `/path1`, data })
},
async doSomething2 ({ dispatch, getters }, { idTree, data }) {
//...
await dispatch('PUT', {
path: `/path2`,
data,
})
},
async doSomething3 ({ dispatch, commit, getters }, { nextIndex }) {
//...
const json = await dispatch('GET', `/path3?query`)
commit('setData3', json)
},
async doSomething4 ({ dispatch, commit, getters }, { nextIndex }) {
//...
const json = await dispatch('GET', `/path4?query`)
commit('setData4', json)
},
}
聰明的例子還有很多,但是我希望神可以多讓我遇到,拜託!!
[1]: 自作聰明 - 教育百科
[2]: Nuxt - 使用 Vue.js 做 SSR 的第一哩路, 05. 產生簡單頁面